import fs from "fs-extra";
import path from "path";
import FastGlob from "../node_modules/fast-glob/out/index.js";

interface IBuild {
    user: string
    yyyymmdd: number
    hhmmss: number
    success: boolean
    duration: number
}

interface ISumary {
    totalCnt: number
    failedCnt: number
    totalDuration: number
    latest: IBuild
    longest: IBuild
    callerMap: { [user: string]: IBuild[] }
}

export class Stat {

    private static ins: Stat;
    public static get Instance(): Stat {
        if(!Stat.ins) Stat.ins = new Stat();
        return Stat.ins;
    }

    private jobRoots!: string[];
    public setJobRoots(value: string[]): void {
        this.jobRoots = value;
    }

    public async sum(jobs: string[], year: string): Promise<ISumary> {
        let totalCnt = 0, failedCnt = 0, totalDuration = 0, latest!: IBuild, longest!: IBuild;
        const callerMap: { [user: string]: IBuild[] } = {};
        for (const jb of this.jobRoots) {
            if (!fs.existsSync(jb)) continue;
            for (const job of jobs) {
                const builds = await FastGlob(`${job}*/builds/*/build.xml`, { cwd: jb });
                for (const b of builds) {
                    const [yyyy_mm_dd, hh_mm_ss] = path.dirname(b).substring(path.dirname(b).lastIndexOf('/') + 1).split('_');
                    if (!yyyy_mm_dd.startsWith(year)) continue;
                    
                    totalCnt++;
    
                    const buildFile = path.join(jb, b);
                    const content = await fs.readFile(buildFile, 'utf-8');
    
                    let user = '';
                    const mch = content.match(/<authenticationName>(\w+)<\/authenticationName>/);
                    if (mch != null) {
                        user = mch[1];
                    }
    
                    let duration = 0;
                    const dmch = content.match(/<duration>(\d+)<\/duration>/);
                    if (dmch != null) {
                        duration = Math.floor(Number(dmch[1]) / 1000);
                        totalDuration += duration;
                    }
    
                    let success = true;
                    if (content.includes('<result>FAILURE</result>')) {
                        success = false;
                        failedCnt++;
                    }
    
                    const yyyymmdd = Number(yyyy_mm_dd.replaceAll('-', ''));
                    const hhmmss = Number(hh_mm_ss.replaceAll('-', ''));
    
                    const build = { user, yyyymmdd, hhmmss, success, duration };
                    if (user) {
                        let arr = callerMap[user];
                        if (arr == null) callerMap[user] = arr = [];
                        arr.push(build)
                    }
    
                    if (latest! == null || this.compareHHmmss(latest.hhmmss, build.hhmmss) < 0) {
                        latest = build;
                    }
    
                    if (longest! == null || longest.duration < build.duration) {
                        longest = build;
                    }
                }
            }
        }
        return { totalCnt, failedCnt, totalDuration, latest, longest, callerMap };
    }

    private compareHHmmss(a: number, b: number): number {
        const hha = Math.floor(a / 10000);
        const hhb = Math.floor(b / 10000);
        if (hha < 7) a += 2400000;
        if (hhb < 7) b += 2400000;
        return a - b;
    }

}